package com.Jano.interceptor;/**
 * @ClassName : JwtTokenInterceptor
 * @Description : token校验拦截
 * @Author : Jano
 * @Date: 2022-07-15 15:12
 */

import com.Jano.dto.JsonResult;
import com.Jano.util.jwt.Constant;
import com.Jano.util.jwt.JwtTokenUtil;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.Objects;

/**
 * token校验拦截
 *
 * @author zoumaoji
 * @date 2022/07/15 15:12
 **/
@Component
public class JwtTokenInterceptor implements HandlerInterceptor {
    /**
     * @param request
     * @param response
     * @param handler
     * @return boolean
     * @author zoumaoji
     * @date 2022/07/15 15:13
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        JsonResult jsonResult = new JsonResult();
        //1.token是否未携带
        //2.token是否有效
        response.setContentType("text/html;charset=utf-8");
        //ACCESS_TOKEN在jwt的常量包中 这里是获取JWT签发的token
        String token = request.getHeader(Constant.ACCESS_TOKEN);
        //token不存在的情况
        if (StringUtils.isBlank(token)) {
            //未经授权的状态码 未携带token的情况
            jsonResult.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
            jsonResult.setErrMsg("please login!！");
            response.getWriter().write(JSON.toJSONString(jsonResult));
            response.getWriter().close();
            return false;
        }
        ;
        //检验token是否成功 1.是否合法 2。是否过期 这两个同时满足才可以
        if (!JwtTokenUtil.validateToken(token)) {
            //未经授权的状态码 token非法的情况
            jsonResult.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
            jsonResult.setErrMsg("token invalid!!");
            response.getWriter().write(JSON.toJSONString(jsonResult));
            response.getWriter().close();
            return false;
        }
        /**为了专门抛出token过期的情况这里写出来,因为在上面的底层中如下
         laims claimsFromToken = getClaimsFromToken(token);
         获取数据是否为空&&token是否过期
         return (null != claimsFromToken && !isTokenExpired(token));
         getClaimsFromToken(token)底层也会校验时间是否过期
         我在测试的时候将token的过期时间设置为10s
         就希望抛出的异常是token expired!! 然而时间过期的异常被getClaimsFromToken(token)这个函数抛出了
         如下：
         public static Claims getClaimsFromToken(String token) {
                Claims claims;
                    try {
                    claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(secretKey)).parseClaimsJws(token).getBody();
             } catch (Exception e) {
                claims = null;
             }
            return claims;
         }
         此时抛出的异常被捕获变成null到了拦截器层就直接返回给前端显示我的异常消息,此处证明了
         Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(secretKey)).parseClaimsJws(token).getBody();
         会检验时间是否过期,如果过期会抛出io.jsonwebtoken.ExpiredJwtException: JWT expired at 2022-07-16T23:33:28Z.
         Current time: 2022-07-16T23:33:37Z, a difference of 9200 milliseconds.  Allowed clock skew: 0 milliseconds
         那么如何将过期时间和非法token这两个异常分开情况来进行抛出??????
         暂时没有更好的办法了我即使写了下面的这段逻辑,就算满足条件也到不到这个方法中,所以我换一个思路,就直接统一的给token invalid!!就可以了
         然后前端只要拿到500异常就刷新token把如果在刷新token的过程中还是报错那就重新登陆了这样也可以的
         ‼️ 主要的无语点在于Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(secretKey)).parseClaimsJws(token).getBody();
         在执行的过程是会校验token是否过期的
         if (JwtTokenUtil.isTokenExpired(token)) {
            jsonResult.setCode(HttpStatus.REQUEST_TIMEOUT.value());
            jsonResult.setErrMsg("token expired!!");
            response.getWriter().write(JSON.toJSONString(jsonResult));
            return false;
         }
         */
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}
